package com.foundationmade.newbiz.business.founder.service;

import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.foundationmade.newbiz.business.founder.domain.Founder;
import com.foundationmade.newbiz.business.founder.domain.FounderHistory;

import devcken.hibernate.query.OrderBy;
import devcken.utility.Pair;

/**
 * 창업주에 대한 데이터베이스 액세스를 제공한다.
 * @author Devcken
 */
@Service("founderService")
@Transactional
public class FounderService
{
	/**
	 * NewBiz {@link org.hibernate.SessionFactory}를 주입받는다.
	 */
	@Resource(name="newbizSessionFactory")
	private SessionFactory _sessionFactory;
	
	/**
	 * 주어진 검색 조건으로 창업주 목록을 조회한다.
	 * @param searchCondition 창업주 목록을 조회하기 위한 검색 조건을 설정한다. 
	 * @param page 표시할 페이지를 설정한다.
	 * @param pageSize 한 페이지 당 표시할 레코드 수를 설정한다.
	 * @param sortConditions 정렬 조건을 설정한다.
	 * @return 주어진 검색 조건에 대한 창업주 목록이 반환된다.
	 */
	@SuppressWarnings("unchecked")
	public Integer listFounders(Founder searchCondition,
			int page,
			int pageSize,
			List<Pair<String, OrderBy>> sortConditions,
			List<Founder> founders)
	{
		Session session = this._sessionFactory.openSession();
		
		try
		{
			Criteria criteria = session.createCriteria(Founder.class);
			
			if (StringUtils.isNotEmpty(searchCondition.getFounderName()))
			{
				criteria.add(Restrictions.like("founderName", String.format("%%%s%%", searchCondition.getFounderName())));
			}
			
			if (StringUtils.isNotEmpty(searchCondition.getCellNumber()))
			{
				criteria.add(Restrictions.like("cellNumber", String.format("%%%s%%", searchCondition.getCellNumber())));
			}
			
			if (searchCondition.getRegion() != null && searchCondition.getRegion() > 0)
			{
				criteria.add(Restrictions.eq("region", searchCondition.getRegion()));
			}
			
			if (searchCondition.getAge() != null && searchCondition.getAge() > 0)
			{
				criteria.add(Restrictions.eq("age", searchCondition.getAge()));
			}
			
			if (searchCondition.getGender() != null && searchCondition.getGender() > 0)
			{
				criteria.add(Restrictions.eq("gender", searchCondition.getGender()));
			}
			
			if (searchCondition.getInflowRoute() != null && searchCondition.getInflowRoute() > 0)
			{
				criteria.add(Restrictions.eq("inflowRoute", searchCondition.getInflowRoute()));
			}
			
			if (searchCondition.getInChargeId() != null && searchCondition.getInChargeId() > 0)
			{
				criteria.add(Restrictions.eq("inChargeId", searchCondition.getInChargeId()));
			}
			
			if (sortConditions.size() == 0)
			{
				criteria.addOrder(Order.desc("generatedTimestamp"));
			}
			
			for (int index = 0; index < sortConditions.size(); index++)
			{
				Pair<String, OrderBy> sortCondition = sortConditions.get(index);
				
				switch (sortCondition.getRight())
				{
					case Ascending:
						
						criteria.addOrder(Order.asc(sortCondition.getLeft()));
						
						break;
						
					case Descending:
						
						criteria.addOrder(Order.desc(sortCondition.getLeft()));
						
						break;
				}
			}
			
			Integer filteredCount = ((Long)criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
			
			criteria.setProjection(null);
			criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
			
			criteria.setFirstResult(pageSize * (page - 1)).setMaxResults(pageSize);
			
			founders.addAll(criteria.list());
			
			return filteredCount;
		}
		finally
		{
			if (session != null && session.isOpen())
			{
				session.close();
			}
		}
	}
	
	/**
	 * 창업자 정보 개수를 가져온다.
	 * @return 창업자 정보 개수가 반환된다.
	 */
	public Long countFounders()
	{
		Session session = this._sessionFactory.openSession();
		
		try
		{
			return (Long)session.createCriteria(Founder.class).setProjection(Projections.rowCount()).uniqueResult();
		}
		finally
		{
			if (session != null && session.isOpen())
			{
				session.close();
			}
		}
	}
	
	/**
	 * 주어진 창업주 아이디에 대한 창업주 정보를 열람한다.
	 * @param founderId 열람하려는 창업주의 아이디를 설정한다.
	 * @return 주어진 창업주 아이디에 대한 창업주 정보가 반환된다. 주어진 창업주 아이디에 대한 창업주 정보가 존재하지 않는 경우 null이 반환된다.
	 */
	public Founder getFounder(Long founderId)
	{
		Session session = this._sessionFactory.openSession();
		
		try
		{
			Criteria criteria = session.createCriteria(Founder.class)
					.add(Restrictions.eq("founderId", founderId));
			
			Founder founder = (Founder)criteria.uniqueResult();
			
			return founder;
		}
		finally
		{
			if (session != null && session.isOpen())
			{
				session.close();
			}
		}
	}
	
	/**
	 * 창업주 정보를 저장한다.
	 * @param founder 저장하려는 창업주 정보를 설정한다.
	 * @return 창업주 정보가 저장되면 true, 그렇지 않으면 false가 반환된다.
	 */
	public boolean saveFounder(Founder founder)
	{
		Session session = this._sessionFactory.openSession();
		
		Transaction transaction = session.beginTransaction();
		
		try
		{
			if (founder.getFounderId() > 0)
			{
				session.update(founder);
			}
			else
			{
				session.save(founder);
			}
			
			transaction.commit();
			
			return true;
		}
		catch (Exception error)
		{
			transaction.rollback();
			
			throw error;
		}
		finally
		{
			if (session != null && session.isOpen())
			{
				session.close();
			}
		}
	}
	
	/**
	 * 창업주 작업 내역 목록을 조회한다.
	 * @param founderId 조회하려는 작업 내역 목록의 창업주 아이디를 설정한다.
	 * @return 창업주 아이디에 해당하는 창업주 작업 내역이 반환된다.
	 */
	@SuppressWarnings("unchecked")
	public List<FounderHistory> listFounderHistories(Long founderId)
	{
		Session session = this._sessionFactory.openSession();
		
		try
		{
			Criteria criteria = session.createCriteria(FounderHistory.class)
					.add(Restrictions.eq("founder.founderId", founderId))
					.addOrder(Order.desc("generatedTimestamp"));
		
			List<FounderHistory> founderHistories = criteria.list();
			
			return founderHistories;
		}
		finally
		{
			if (session != null && session.isOpen())
			{
				session.close();
			}
		}
	}

	/**
	 * 창업주 작업 내역 정보를 저장한다.
	 * @param founderHistory 저장하려는 창업주 작업 내역 정보를 설정한다.
	 * @return 창업주 작업 내역이 저장되면 true, 그렇지 않으면 false가 반환된다.
	 */
	public boolean saveFounderHistory(FounderHistory founderHistory)
	{
		Session session = this._sessionFactory.openSession();
		
		Transaction transaction = session.beginTransaction();
		
		try
		{
			session.saveOrUpdate(founderHistory);
			
			transaction.commit();
			
			return true;
		}
		catch (Exception error)
		{
			transaction.rollback();
			
			throw error;
		}
		finally
		{
			if (session != null && session.isOpen())
			{
				session.close();
			}
		}
	}

	/**
	 * 창업주 작업 내역을 삭제한다.
	 * @param founderHistoryId 삭제하려는 창업주 작업 내역의 아이디를 설정한다.
	 * @return 작업 내역이 삭제되면 true, 그렇지 않으면 false가 반환된다.
	 */
	public boolean deleteFounderHistory(Long founderHistoryId)
	{
		Session session = this._sessionFactory.openSession();
		
		Transaction transaction = session.beginTransaction();
		
		try
		{
			FounderHistory founderHistory = (FounderHistory)session.get(FounderHistory.class, founderHistoryId);
			
			session.delete(founderHistory);
			
			transaction.commit();
			
			return true;
		}
		catch (Exception error)
		{
			transaction.rollback();
			
			throw error;
		}
		finally
		{
			if (session != null && session.isOpen())
			{
				session.close();
			}
		}
	}
}